#include <stdio.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <fcntl.h>


#define L 1
#define G 2
#define P 3
#define E 4

typedef struct 
{
    int type;
    char name[128];
    char data[512];
    int len;
}Mode;

void list_file(int lfd);
void get_file(int lfd, char *choice);
void put_file(int cfd, char *choice);

int main(int argc, const char *argv[])
{
    int lfd;
    char choice[100];
    struct sockaddr_in serveraddr;

    if(argc != 3)
    {
	printf("usage:%s serverip port.\n", argv[0]);
	return -1;
    }

    if((lfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
	perror("fail to socket:");
	return -1;
    }

    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));

    if(connect(lfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
    {
	perror("fail to conect:");
	return -1;
    }

next:
    printf("*************************\n");
    printf("***请输入help查看选项****\n");
    printf("*************************\n");
    printf("input your choice:>>>");

    bzero(choice, sizeof(choice));
    fgets(choice, sizeof(choice), stdin);

    //去掉换行符
    if(choice[strlen(choice) - 1] == '\n')
	choice[strlen(choice) - 1] = '\0';

    if(strcmp(choice, "help") != 0)
    {
	printf("Input invalid.\n");
	goto next;
    }



    while(1)
    {
	printf("***********************************************\n");
	printf("******输入/输出********************************\n");
	printf("******list:查看服务器所在目录的所有文件********\n");
	printf("******get filename:下载服务器目录的文件********\n");
	printf("******put filename:上传文件到服务器************\n");
	printf("******quit:关闭客户端**************************\n");
	printf("***********************************************\n");
	printf("input your choice:>>");

	bzero(choice, sizeof(choice));
	fgets(choice, sizeof(choice), stdin);

	//去掉换行符
	if(choice[strlen(choice) - 1] == '\n')
	    choice[strlen(choice) - 1] = '\0';

	if(strncmp(choice, "list", 4) == 0)
	{
	    list_file(lfd);
	}
	else if((strncmp(choice, "get", 3) == 0 ) && choice[3] == ' ')
	{
	    get_file(lfd, choice);
	}
	else if((strncmp(choice, "put", 3) == 0) && choice[3] == ' ')
	{
	    put_file(lfd, choice);
	}
	else if(strncmp(choice, "quit", 4) == 0)
	{
	    break;
	}
	else
	{
	    printf("Input invalid.\n");
	}
    }

    close(lfd);
    return 0;
}

//查看当前目录所有文件
void list_file(int lfd)
{
    Mode mode;
    mode.type = L;

    if(send(lfd, &mode, sizeof(mode), 0) < 0)
    {
	printf("%s--send--%s", __func__, strerror(errno));
	return ;
    }

    if(recv(lfd, &mode, sizeof(mode), 0) < 0)
    {
	printf("%s--recv--%s", __func__, strerror(errno));
	return ;
    }

    char *pch;
    pch = strtok(mode.data, "|");
    while(pch != NULL)
    {
	printf("***%s\n", pch);
	pch = strtok(NULL, "|");
    }

    printf("服务器目录已经接收完毕\n");

}


//从服务器下载文件到客户端
void get_file(int lfd, char *choice)
{
    Mode mode;
    mode.type = G;
    char *ret;
    int fp;
    int flag = 1;

    if((ret = strchr(choice, ' ')) == NULL)
    {
	printf("Input file name invalid\n");
	return ;
    }

    bzero(mode.name, sizeof(mode.name));
    strcpy(mode.name, ++ret);

    //给服务端发送文件名
    if(send(lfd, &mode, sizeof(mode), 0) < 0)
    {
	printf("%s--send--%s", __func__, strerror(errno));
	return ;
    }

    //接收服务端数据
    while(1)
    {
	if(recv(lfd, &mode, sizeof(mode), 0) < 0)
	{
	    printf("%s--recv--%s", __func__, strerror(errno));
	    break ;
	}

	//判断是否有异常或已读完
	if(mode.type == E)
	{
	    printf("%s\n", mode.data);
	    if(flag == 0)
		close(fp);
	    break;
	}

	//创建并打开文件
	if(flag)
	{
	    if((fp = open(mode.name, O_CREAT|O_RDWR, 0777)) < 0)
	    {
		printf("File can not open to write\n");
		break;
	    }
	    flag = 0;
	}

	//向文件中写数据
	if(write(fp, mode.data, mode.len) < 0)
	{
	    printf("%s--write--%s", __func__, strerror(errno));
	    break ;
	}
    }
}

//向服务端上传文件
void put_file(int cfd, char *choice)
{
    Mode mode;
    mode.type = P;
    char *ret;
    int fp;
    int len;

    if((ret = strchr(choice, ' ')) == NULL)
    {
	printf("Input file name invalid\n");
	return ;
    }

    bzero(mode.name, sizeof(mode.name));
    strcpy(mode.name, ++ret);


    //打开相应文件
    if((fp = open(mode.name, O_RDONLY, 0777)) < 0)
    {
	printf("%s--send--%s\n", __func__, strerror(errno));
	return ;
    }

    //文件传送
    while((len = read(fp, mode.data, sizeof(mode.data))) > 0)
    {
	mode.len = len;
	if(send(cfd, &mode, sizeof(Mode), 0) < 0)
	{
	    printf("%s--send--%s\n", __func__, strerror(errno));
	    return ;
	}

	bzero(mode.data, sizeof(mode.data));
    }

    //传送完成
    mode.type = E;
    bzero(mode.data, sizeof(mode.data));
    strcpy(mode.data, "接收文件成功");
    if(send(cfd, &mode, sizeof(Mode), 0) < 0)
    {
	printf("%s--send--%s\n", __func__, strerror(errno));
    }


    close(fp);
    printf("上传完毕\n");
}
